#include "DivSelBase.h"

#include "Joueur.h"

#include "SelectionComp.h"

#include <QtGui/QPushButton>
#include <QtGui/QButtonGroup>

#include <QtGui/QApplication>

#include <algorithm>

using namespace std;

/** Constructeur par défaut.
 * On lit les compétences déjà connues avec Joueur::diverses,
 * détermine les coûts en fonctions des accès.
 *
 * Il faut également vider le conteneur boutons, car ici on en veut 3
 * : "OK", qui sélectionne la catégorie, "Terminer", qui ferme la
 * fenêtre et applique les changements et "Annuler", qui ferme la
 * fenêtre.
 *
 * Le niveau de sortie est paramétré par BaseUI::interne :\n
 * - \e FUNC affiche les messages de début et de fin de méthode.
 *
 * @param nbr nombre de compétences.
 * @param ptr pointeur sur le premier éléments de la liste des noms de
 * catégories.
 * @param j joueur pour lequel on veut sélectionner de nouvelles
 * compétences diverses.
 * @param parent pointeur sur le widget parent (orphelin par défaut).
 */
DivSelBase::DivSelBase(const unsigned& nbr, const string* ptr,
		       Joueur* j, QWidget* parent)
  : BaseMultSel( nbr, ptr, "Comp. diverses", "DivSelBase", parent )
{
  /*Debug::*/empileNiveau( &interne );
  func() << "DivSelBase::DivSelBase -> début" << endmsg;

  joueur = j;

  accesJoueur =  joueur -> acces(nbrAccess);

  compDejaPrises = joueur -> diverses( nbrCompDejaPrises );
  Begin = compDejaPrises -> begin();
  End  = compDejaPrises -> end();

  prepareBoutons();

  setFenetreLayout();

  func() << "DivSelBase::DivSelBase -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/** Constructeur de copie.
 * Permet de dupliquer une instance de DivSelBase.
 *
 * @param divSel instance à dupliquer.
 */
DivSelBase::DivSelBase(const DivSelBase& divSel)
  : BaseMultSel( divSel )
{
  /*Debug::*/empileNiveau( &interne );
  func() << "DivSelBase::DivSelBase -> début" << endmsg;

  joueur = divSel.joueur;

  accesJoueur =  joueur -> acces(nbrAccess);

  compDejaPrises = joueur -> diverses( nbrCompDejaPrises );
  Begin = compDejaPrises -> begin();
  End  = compDejaPrises -> end();

  prepareBoutons();

  setFenetreLayout();

  func() << "DivSelBase::DivSelBase -> fin" << endmsg;
  /*Debug::*/depileNiveau();  
}

/**
 * Destructeur, ne fait rien de spécial
 */
DivSelBase::~DivSelBase()
{}

/** Affiche la fenêtre et permet d'effectuer le choix des compétences.
 * Le fonctionnement est entièrement dicté par les structures
 * présente, et la machinerie se trouve principalement dans
 * selectionner().
 *
 * @param vec conteneur des compétences choisies, est écrit dans la
 * méthode si le choix est validé, sinon il est simplement
 * réinitialisé.
 * @return StatusCode \e true si choix validé, \e false sinon.
 */
StatusCode DivSelBase::compDivSelection(vector<unsigned>& vec)
{
  this -> show();

  qApp -> exec();

  if ( OK )
    vec.assign( compChoisies.begin(), compChoisies.end());
  else
    vec.clear();

  return StatusCode(OK);
}

void DivSelBase::prepareBoutons()
{

  while (! boutons.empty())
    {
      delete boutons.back();
      boutons.pop_back();
    }

  boutons.push_back( new QPushButton( trUtf8("&Quitter"), this ) );
  boutons.back() -> setToolTip( trUtf8("Abandonner le programme") );
  connect( boutons.back()  , SIGNAL( clicked() ), this, SLOT( annuler() ) );
  boutons.push_back( new QPushButton( trUtf8("&Terminer"), this ) );
  boutons.back() -> setToolTip( trUtf8("Quitter la sélection des compétences martiales") );
  connect( boutons.back()  , SIGNAL( clicked() ), this, SLOT( fermer() ) );
  boutons.push_back( new QPushButton( trUtf8("&OK"), this ) );
  boutons.back() -> setToolTip( trUtf8("Sélectionner les compétences de cette catégorie") );
  connect( boutons.back(), SIGNAL( clicked() ), this, SLOT( selectionner() ) );
}

/**
 * Est appelé lorsque le bouton "OK" est pressé. On crée la liste de
 * compétences relatives à la catégorie sélectionnée (Combattants,
 * Roublards, ...), avec les coûts (éventuellement modifiés si pas
 * accès). On regarde aussi quelles sont les compétences qui sont déjà
 * connues par le PJ, afin d'éviter qu'il les sélectionne à nouveau.
 *
 * Ensuite, on affiche un popup qui permet de sélectionner les
 * éléments de cette liste. Si ce popup est fermé en validant le
 * choix, alors on met à jour le conteneur compChoisies et le nombre
 * de PP restants. Attention, le nombre de PP est diminué mais les
 * compétences ne sont pas mises à jour ici... il faudrait peut-être
 * changer ça.
 *
 * La sélections des compétences se fait par la classe SelectionComp.
 *
 * Le niveau de sortie est paramétré par BaseUI::interne :\n
 * - \e FUNC affiche les messages de début et de fin de méthode.\n
 * - \e LINFO affiche les compétences que l'on va pouvoir choisir et
 * ensuite les numéros des compétences sélectionnées.\n
 * - \e DEBUG affiche le numéro de la catégorie choisie et ensuite le
 * numéro de la première compétence de la catégorie ainsi que le
 * nombre de compétences dans cette catégorie.
 */
void DivSelBase::selectionner()
{
  /*Debug::*/empileNiveau( &interne );
  func() << "DivSelBase::selectionner -> début" << endmsg;

  unsigned catNumber(100), i, debut, nbr;

  const vector< NonMartiale > * listeCompetences;
  unsigned nbrCompetences;

  vector<unsigned> choix;

  vector<string>       compCategorie;
  vector<unsigned> compCout;

  listeCompetences = joueur -> listeCompetences(nbrCompetences);

  debut = nbrCompetences;
  nbr = 0;

  for (i = 0; i < dimension; i++)
    {
      if ( groupe -> button(i) -> isChecked() )
	{
	  catNumber = i;
	  break;
	}
    }
  
  debug() << "A choisi " << catNumber << endmsg;
  
  for (i = 0; i < nbrCompetences; i++)
    {
      if ( static_cast<unsigned>( listeCompetences -> at( i ) . 
				  categorieAdmise() ) == catNumber )
	{
	  linfo() << listeCompetences -> at( i ) . nom() << endmsg;
	  if (i < debut) debut = i;
	  compCategorie.push_back( listeCompetences -> at( i ) . nom() );
	  if ( std::find( accesJoueur -> begin(), accesJoueur -> end(),
			  static_cast<TypeClasse>(catNumber) )
	       != accesJoueur -> end() )
	    compCout.push_back( listeCompetences -> at( i ) . prix() );
	  else
	    compCout.push_back( listeCompetences -> at( i ) . prix() + 5);
	}
    }
  
  nbr = compCategorie.size();

  aDeja.assign(nbr, false);

  for (i = 0; i < nbr; i++)
    {
      It = std::find(Begin, End, i + debut);
      if (It != End && static_cast<unsigned>(It - Begin) % 2 == 0)
	{
	  aDeja[i] = true;
	}
    }
  
  debug() << "Première " << debut << ", nombre " << nbr << endmsg;

  string nomGroupe(Liste[catNumber] + " :");

  SelectionComp enfant(nbr, &compCategorie[0],
		       aDeja, nomGroupe, &compCout[0],
		       joueur -> nbrPP(), this);

  StatusCode selComp( enfant.selectionFaite(choix) );

  if ( selComp )
    {
      vector<unsigned>::iterator it, Begin(choix.begin()),
	End(choix.end());

      for (it = Begin; it != End; it++)
	{
	  linfo() << *it + debut << ' ';
	  compChoisies.push_back( *it + debut );
	}
      linfo() << endmsg;
      joueur -> setPP( static_cast<unsigned>( selComp.valeur() ) );

      it = unique(compChoisies.begin(), compChoisies.end());

      compChoisies.erase( it, End );
    }

  func() << "DivSelBase::selectionner -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}
